feat: Add MCP parser plugin and body access infrastructure#361
Conversation
Add the mcp-parser plugin -- the first plugin that requires body access. It parses MCP JSON-RPC requests (tools/call, resources/read, prompts/get) and populates pctx.Extensions.MCP for downstream policy plugins. Body access infrastructure: - Pipeline.NeedsBody() checks if any plugin declares BodyAccess - ext_proc: two-phase processing via ModeOverride BUFFERED - forward/reverse proxy: conditional io.ReadAll before pipeline run - Startup validation rejects body-access plugins in waypoint mode The mcp-parser is registered but NOT in default pipelines -- users opt in via config. This prevents body buffering overhead for deployments that do not need MCP awareness. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
Prevent OOM from oversized request bodies when body-access plugins are configured. Uses http.MaxBytesReader with a 1MB limit matching Envoy's default per_stream_buffer_limit_bytes. Returns 413 for oversized bodies. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
Step-by-step instructions for enabling mcp-parser via the authbridge-runtime-config ConfigMap, including log verification and troubleshooting. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
| "github.com/kagenti/kagenti-extensions/authbridge/authlib/pipeline" | ||
| ) | ||
|
|
||
| type MCPParser struct{} |
There was a problem hiding this comment.
Could use a descriptive comment?
| ## Prerequisites | ||
|
|
||
| - A running Kagenti cluster (Kind or OpenShift) with the Ansible installer | ||
| completed |
There was a problem hiding this comment.
Does it matter what kind of Kubernetes cluster, and how Kagenti was installed?
| completed | ||
| - An agent namespace (e.g., `team1`) with AuthBridge sidecars injected |
There was a problem hiding this comment.
| completed | |
| - An agent namespace (e.g., `team1`) with AuthBridge sidecars injected | |
| completed | |
| - A namespace (e.g., `team1`) with labeled with `kagenti-enabled: "true"` for AuthBridge sidecar injection. |
esnible
left a comment
There was a problem hiding this comment.
Clean, well-structured PR. The NeedsBody() introspection avoids buffering overhead when no plugin needs it, ext_proc uses ModeOverride to dynamically request bodies from Envoy, and forward/reverse proxy paths use MaxBytesReader for OOM protection. Waypoint startup validation is a good safety net. Test coverage is thorough — 10 unit tests for the parser, 7 body-buffering integration tests across all 3 listener modes.
Areas reviewed: Go (plugin, pipeline, all 3 listeners, main), Tests, Docs, Security
Commits: 3/3 signed-off
CI: 16/16 passing
| } | ||
|
|
||
| func (p *bodyRecorderPlugin) Name() string { return "body-recorder" } | ||
| func (p *bodyRecorderPlugin) Capabilities() pipeline.PluginCapabilities { |
There was a problem hiding this comment.
suggestion: bodyRecorderPlugin is defined identically in 3 test files (extproc, forwardproxy, reverseproxy). Consider extracting to a shared testutil package to avoid triple-maintenance. Not blocking since the type is small.
| "net/url" | ||
|
|
||
| "github.com/kagenti/kagenti-extensions/authbridge/authlib/pipeline" | ||
| ) |
There was a problem hiding this comment.
suggestion: maxBodySize is defined independently in both forwardproxy and reverseproxy. If the limit ever changes, they could drift. Consider a shared constant (e.g., in pipeline or a listener/common package). Low priority since there are only two today.
| if p.NeedsBody() { | ||
| slog.Debug("ext_proc: requesting body from Envoy", "direction", direction) | ||
| pendingHeaders = headers | ||
| pendingDirection = direction |
There was a problem hiding this comment.
suggestion: The ext_proc path relies on Envoy's per_stream_buffer_limit_bytes (default 1MB) to bound body size, unlike the forward/reverse proxy paths which enforce MaxBytesReader explicitly. If an operator changes Envoy's buffer limit, ext_proc silently accepts larger bodies. Consider documenting this assumption or adding a size check after receiving RequestBody.
| ctx := stream.Context() | ||
|
|
||
| var pendingHeaders *corev3.HeaderMap | ||
| var pendingDirection string |
There was a problem hiding this comment.
nit: pendingHeaders/pendingDirection are scoped to the entire Process function but only meaningful between a RequestHeaders and RequestBody message. A brief comment noting the Envoy protocol guarantees that prevent stale state would help future readers.
- Add doc comment on MCPParser struct - Add comment explaining ext_proc pendingHeaders/pendingDirection lifecycle - Add body size enforcement in ext_proc (maxBodySize = 1MB) with test - Clarify README prerequisites: cluster type, namespace label Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
|
All comments are addressed. Thanks @esnible! |
- Add doc comment on MCPParser struct - Add comment explaining ext_proc pendingHeaders/pendingDirection lifecycle - Add body size enforcement in ext_proc (maxBodySize = 1MB) with test - Clarify README prerequisites: cluster type, namespace label Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
Summary
tools/call,resources/read,prompts/get) and populatespctx.Extensions.MCPfor downstream policy pluginsPipeline.NeedsBody()introspects plugin capabilitiesModeOverridewithProcessingMode_BUFFEREDio.ReadAllbefore pipeline executionThe mcp-parser is registered but NOT added to default pipelines — users opt in via YAML config. This prevents body buffering overhead for deployments that don't need MCP awareness.
Context
This is the first Phase 2 deliverable from the plugin architecture proposal. PRs #358 and #359 established the pipeline with
jwt-validationandtoken-exchange. This PR adds the first plugin that couldn't exist without body access.The MCP parser enables future plugins (tool-policy, audit, guardrails) to make authorization decisions at the MCP tool level — the core value proposition of the plugin architecture.
Test plan
go test ./authlib/... ./cmd/authbridge/...go vetcleanAssisted-By: Claude (Anthropic AI) noreply@anthropic.com